package com.smsc.utils;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.io.FileUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.yaml.snakeyaml.Yaml;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class DataSourceUtils {

    public static DataSource INSTANCE;

    public static MybatisSqlSessionFactoryBean SQL_SESSION_INSTANCE;

    public static MybatisSqlSessionFactoryBean PG_SQL_SESSION_INSTANCE;




    public static DataSource getUnitTestDataSource() throws SQLException {

        if (INSTANCE != null) {
            return INSTANCE;
        }
        HikariDataSource result = new HikariDataSource();

        result.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        result.setJdbcUrl("jdbc:oracle:thin:@192.168.135.228:1521:ORCL");
        result.setUsername("hes65_dev01");
        result.setPassword("test");
        result.setAutoCommit(false);
        INSTANCE = result;
        return result;

    }

    public static SqlSession getUnitTestSqlSession(Class mapper) throws Exception {
        if (SQL_SESSION_INSTANCE != null) {
            SQL_SESSION_INSTANCE.getConfiguration().addMapper(mapper);
            return SQL_SESSION_INSTANCE.getObject().openSession();
        }

        MybatisConfiguration configuration  = new MybatisConfiguration();

        configuration.getMapperRegistry().addMapper(mapper);
//        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//        bean.setConfiguration(configuration);
//        bean.setDataSource(getUnitTestDataSource());

        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setConfiguration(configuration);
        mybatisSqlSessionFactoryBean.setDataSource(getUnitTestDataSource());
        SQL_SESSION_INSTANCE = mybatisSqlSessionFactoryBean;


        return SQL_SESSION_INSTANCE.getObject().openSession();
    }


    public static RedisTemplate redisTemplate () throws IOException {


        Yaml yaml = new Yaml();
        InputStream inputStream = null;
        try {
            inputStream = DataSourceUtils.class.getClassLoader().getResourceAsStream("bootstrap-junit.yml");
        } catch (Exception ex) {
            inputStream = FileUtils.openInputStream(new File("/home/udis/run/config/bootstrap-junit.yml"));
        }
        Map<String, Object> obj = yaml.load(inputStream);



        String pattern = "yyyy-MM-dd HH:mm:ss";
        LettuceConnectionFactory factory = buildLettuceFactory(obj);

        //创建Redis缓存操作助手RedisTemplate对象
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(factory);
        //以下代码为将RedisTemplate的Value序列化方式由JdkSerializationRedisSerializer更换为Jackson2JsonRedisSerializer
        //此种序列化方式结果清晰、容易阅读、存储字节少、速度快，所以推荐更换
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 解决jackson2无法反序列化LocalDateTime的问题
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        //序列化器
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern)));
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
        om.registerModule(javaTimeModule);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();

        return template;

    }

    private static LettuceConnectionFactory buildLettuceFactory(Map<String, Object> obj) {

        RedisStandaloneConfiguration redisStandaloneConfiguration =  new RedisStandaloneConfiguration();
        final Map spring = MapUtil.get(obj, "spring", Map.class);
        final Map redis = MapUtil.get(spring, "redis", Map.class);
        final Integer db = MapUtil.get(redis, "database", Integer.class);
        final String host = MapUtil.get(redis, "host", String.class);
        final Integer port = MapUtil.get(redis, "port", Integer.class);
        redisStandaloneConfiguration.setDatabase(db);
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);

        LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration);
        factory.afterPropertiesSet();

        return factory;
    }

    public static DataSource getPgsqlTestDataSource() throws SQLException {

        if (INSTANCE != null) {
            return INSTANCE;
        }
        HikariDataSource result = new HikariDataSource();

        result.setDriverClassName("org.postgresql.Driver");
        result.setJdbcUrl("jdbc:postgresql://192.168.169.128:5432/wjhdb");
        result.setUsername("test");
        result.setPassword("test");
        result.setAutoCommit(false);
        INSTANCE = result;
        return result;

    }


    public static SqlSession getPgsqlSqlSession(Class mapper) throws Exception {
        if (PG_SQL_SESSION_INSTANCE != null) {
            PG_SQL_SESSION_INSTANCE.getConfiguration().addMapper(mapper);
            return PG_SQL_SESSION_INSTANCE.getObject().openSession();
        }

        MybatisConfiguration configuration  = new MybatisConfiguration();

        configuration.getMapperRegistry().addMapper(mapper);
//        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//        bean.setConfiguration(configuration);
//        bean.setDataSource(getUnitTestDataSource());

        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
//        TransactionFactory transactionFactory = new JdbcTransactionFactory();

//        mybatisSqlSessionFactoryBean.setTransactionFactory(transactionFactory);
        mybatisSqlSessionFactoryBean.setConfiguration(configuration);
        mybatisSqlSessionFactoryBean.setDataSource(getPgsqlTestDataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        mybatisSqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/**/*.xml"));
        PG_SQL_SESSION_INSTANCE = mybatisSqlSessionFactoryBean;


        return PG_SQL_SESSION_INSTANCE.getObject().openSession();
    }


}
